/*
 * LDIR
 *
 * LDIR, a GPS cartography application built for Let's Do It Romania eco
 * campaign.
 * Copyright (C) 2010 Genera Software <office@generasoftware.com>
 *
 * http://generasoftware.com/
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <eikenv.h>
#include <eikappui.h>
#include <eikapp.h>
#include <bautils.h>
#include <s32file.h>
#include <e32math.h>

#include "Settings.h"
#include "globals.h"
#include "WSUtilities.h"
#include "Imei.h"
#include "WasteCache.h"
#include "Logger.h"

CSettings::CSettings() :
	CCoeStatic( KSettingsUID, -1 ), iIap( KErrNotFound )
	{
	// No implementation required
	}

CSettings::~CSettings()
	{
	delete iCurrentWasteInfo;
	delete iLocalCache;
	delete iPendingUploadCache;
	}

CSettings& CSettings::InstanceL()
	{
	CSettings* self =
		static_cast<CSettings*> ( CCoeEnv::Static( KSettingsUID ) );
	if ( NULL == self )
		{
		self = new ( ELeave ) CSettings;
		CleanupStack::PushL( self );
		self->ConstructL();
		CleanupStack::Pop( self );
		}
	return *self;
	}

void CSettings::ConstructL()
	{
	iStorageName = AppDir();
	iStorageName += KSettingsFile;
	iIsFirstRun = ETrue;
	iLocalCache = CWasteCache::NewL();
	iPendingUploadCache = CWasteCache::NewL();
	iUsername = KNullDesC;
	iPassword = KNullDesC;
	}

const TDesC& CSettings::AppDir()
	{
	if ( iAppDir.Length() )
		return iAppDir;

	RFs fs;
	fs.Connect();
	fs.PrivatePath( iAppDir );
	fs.Close();
	return iAppDir;
	}

////////////////////////////////////////////////////////////////////////////////
const TDesC& CSettings::ResourceDir()
	{
	if ( iResourceDir.Length() )
		return iResourceDir;
#ifdef __WINS__
	iResourceDir = _L("c:\\resource\\apps\\");
#else
	iResourceDir = _L("\\resource\\apps\\");
#endif
	return iResourceDir;
	}

////////////////////////////////////////////////////////////////////////////////
const TDesC& CSettings::SplashFile()
	{
	if ( iSplash.Length() )
		return iSplash;
	iSplash = ResourceDir();
	iSplash += KSplashFile;
	return iSplash;
	}

////////////////////////////////////////////////////////////////////////////////
const TDesC& CSettings::MifFile()
	{
	if ( iMifFile.Length() )
		return iMifFile;
	iMifFile = ResourceDir();
	iMifFile += KMifFile;
	return iMifFile;
	}

////////////////////////////////////////////////////////////////////////////////
TBool CSettings::IsFirstRun()
	{
	return iIsFirstRun;
	}

//////////////////////////////////////////////////////////////////////////
void CSettings::ExternalizeL( RWriteStream& aStream ) const
	{
	aStream.WriteInt32L( iIsFirstRun );
	aStream.WriteInt32L( iIap );
	aStream.WriteInt32L( iUsername.Length() );
	aStream.WriteL( iUsername, iUsername.Length() );
	aStream.WriteInt32L( iPassword.Length() );
	aStream.WriteL( iPassword, iPassword.Length() );
	aStream.WriteInt32L( iUserSalt.Length() );
	aStream.WriteL( iUserSalt, iUserSalt.Length() );
	aStream.WriteInt32L( iImei.Length() );
	aStream.WriteL( iImei, iImei.Length() );
	aStream << *iPendingUploadCache;
	aStream << *iLocalCache;
	}

//////////////////////////////////////////////////////////////////////////
void CSettings::InternalizeL( RReadStream& aStream )
	{
	iIsFirstRun = aStream.ReadInt32L();
	iIap = aStream.ReadInt32L();
	TInt length = aStream.ReadInt32L();
	aStream.ReadL( iUsername, length );
	length = aStream.ReadInt32L();
	aStream.ReadL( iPassword, length );
	length = aStream.ReadInt32L();
	aStream.ReadL( iUserSalt, length );
	length = aStream.ReadInt32L();
	aStream.ReadL( iImei, length );
	delete iPendingUploadCache;
	iPendingUploadCache = CWasteCache::NewL();
	aStream >> *iPendingUploadCache;
	delete iLocalCache;
	iLocalCache = CWasteCache::NewL();
	aStream >> *iLocalCache;
	}

//////////////////////////////////////////////////////////////////////////
void CSettings::StoreSettingsL()
	{
	RFs fs;
	User::LeaveIfError( fs.Connect() );
	CleanupClosePushL( fs );

	if ( BaflUtils::FileExists( fs, iStorageName ) )
		{
		BaflUtils::DeleteFile( fs, iStorageName );
		}
	else
		BaflUtils::EnsurePathExistsL( fs, iStorageName );

	RFileWriteStream streamOut;
	User::LeaveIfError( streamOut.Create( fs, iStorageName, EFileWrite ) );
	CleanupClosePushL( streamOut );
	streamOut << *this;
	CleanupStack::PopAndDestroy( 2 );
	SettingsChanged();
	}

//////////////////////////////////////////////////////////////////////////
void CSettings::LoadSettingsL()
	{
	RFs fs;
	User::LeaveIfError( fs.Connect() );
	CleanupClosePushL( fs );

	// Start reading store
	TEntry fileEntry;
	TInt fileSize = 0;
	if ( fs.Entry( iStorageName, fileEntry ) == KErrNone )
		fileSize = fileEntry.iSize;

	if ( fileSize != 0 )
		{
		RFileReadStream streamIn;
		User::LeaveIfError( streamIn.Open( fs, iStorageName, EFileRead ) );
		CleanupClosePushL( streamIn );
		streamIn >> *this;
		CleanupStack::PopAndDestroy( &streamIn );
		}

	CleanupStack::PopAndDestroy( &fs );
	}

////////////////////////////////////////////////////////////////////////////////
void CSettings::ClearIsFirstRunL()
	{
	iIsFirstRun = EFalse;
	StoreSettingsL();
	}

//////////////////////////////////////////////////////////////////////////
const TDesC& CSettings::UserSalt()
	{
	return iUserSalt;
	}

////////////////////////////////////////////////////////////////////////////////
const TDesC& CSettings::Imei()
	{
#ifndef __WINS__
	if (iImei.Length())
	return iImei;

	CImeiGetter::GetIMEIL(iImei);
#else
	iImei = _L("000000000000000");
#endif
	return iImei;
	}

void CSettings::SetUserSalt( const TDesC& aUserSalt )
	{
	iUserSalt = aUserSalt;
	SettingsChanged();
	}

//////////////////////////////////////////////////////////////////////////
TInt32 CSettings::Iap()
	{
	return iIap;
	}

//////////////////////////////////////////////////////////////////////////
void CSettings::SetIap( const TInt32& aValue )
	{
	iIap = aValue;
	SettingsChanged();
	}

TDes& CSettings::Username()
	{
	return iUsername;
	}

void CSettings::SetUsername( const TDesC& aUsername )
	{
	iUsername.Copy( aUsername.Left( iUsername.MaxLength() ) );
	SettingsChanged();
	}

TDes& CSettings::Password()
	{
	return iPassword;
	}

void CSettings::SetPassword( const TDesC& aPassword )
	{
	iPassword.Copy( aPassword.Left( iPassword.MaxLength() ) );
	SettingsChanged();
	}

CWasteCache& CSettings::PendingUploadCache()
	{
	return *iPendingUploadCache;
	}

CWasteCache& CSettings::LocalCache()
	{
	return *iLocalCache;
	}

CWasteInfo* CSettings::WorkingWaste()
	{
	return iCurrentWasteInfo;
	}

void CSettings::SetWorkingWaste(CWasteInfo* aWasteInfo)
	{
	iCurrentWasteInfo = aWasteInfo;
	}

HBufC8* CSettings::GenerateAuthStringLC()
	{
	_LIT8(KOpen, "(");
	_LIT8(KClose, ")");
	__ASSERT_DEBUG(UserSalt() != KNullDesC, User::Invariant());
	TBuf8<KMaxName> param;
	param.Copy( Username() );
	param.Append( KOpen );
	HBufC8* passHash = GeneratePassHashLC();
	param.Append( *passHash );
	param.Append( KClose );
	CleanupStack::PopAndDestroy( passHash );
	LOG(EVerbosityCore, _L8("CSettings::GenerateAuthStringLC() - authorization string: \"%S\""), &param);
	return param.AllocLC();
	}

HBufC8* CSettings::GeneratePassHashLC()
	{
	TBuf8<KMaxName> hashInput;
	hashInput.Copy( Password() );
	hashInput.Append( UserSalt() );
	CMessageDigest* messageDigest = CMD5::NewL();
	CleanupStack::PushL( messageDigest );
	TPtrC8 hash = messageDigest->Hash( hashInput );
	HBufC8* encodedHash = HBufC8::NewL( ( 2 * hash.Length() ) );
	TPtr8 encodedHashPtr = encodedHash->Des();
	for ( TInt i = 0; i < hash.Length(); ++i )
		{
		encodedHashPtr.AppendFormat( _L8("%+02x"), hash[i] );
		}
	CleanupStack::PopAndDestroy( messageDigest );
	CleanupStack::PushL( encodedHash );
	LOG(EVerbosityCore, _L8("CSettings::GeneratePassHashLC() - password hash: \"%S\""), encodedHash);
	return encodedHash;
	}

// End of file
